﻿using Devil;
using System.Buffers;
using UnityEditor.Graphs;
using UnityEngine;

namespace GameToolkit.Task
{
    public class TaskGraphMono : MonoBehaviour, ICullingUpdate
    {
        [SerializeField]
        TaskGraphAsset m_GraphAsset;

        [SerializeField, Tooltip("开启异步线程")]
        bool m_UpdateAsync;

        [SerializeField, Tooltip("执行更新方式（如果不使用 CullingGroupAPI, 该方应选择 Nothing）")]
        ECullingUpdateMode m_UpdateMode;

        [SerializeField, Tooltip("可视范围内刷新距离")]
        ECullDistance m_UpdateDistance = ECullDistance.NearBy;

        int ICullingUpdate.CulledUpdateDistanceLv => Mathf.Max(1, (int)m_UpdateDistance); 

        int ICullingUpdate.AlwaysUpdateDistanceLv => (int)m_UpdateDistance;

        ECullingUpdateMode ICullingUpdate.UpdateMode => m_UpdateMode;

        void ICullingUpdate.OnCullingUpdate(CullingCamera culler, ECullingUpdateMode mode)
        {
            if(mGraph != null)
            {
                mGraph.UpdateTaskGraph(culler.deltaTime);
            }
        }

        void UpdateAsync(float deltaTime)
        {
            if(mGraph != null)
            {
                mGraph.UpdateTaskGraph(deltaTime);
            }
        }

        ParallelDispatcher.Handler mLooper;
        TaskGraph mGraph;
        private void OnEnable()
        {
            if (mGraph == null && m_GraphAsset != null)
            {
                mGraph = new TaskGraph(m_GraphAsset);
            }
            if (mGraph != null)
            {
                mGraph.name = name;
                mGraph.SetOwner(this);
                mGraph.StartGraph();
            }
            if (m_UpdateMode == 0)
                mLooper = ParallelUtils.ScheduleLooper(UpdateAsync, !m_UpdateAsync);
        }

        private void OnDisable()
        {
            mLooper.Abort();
            if (mGraph != null)
            {
                mGraph.StopGraph();
            }
        }

        private void OnDestroy()
        {
            if (mGraph != null)
            {
                mGraph.Dispose();
                mGraph = null;
            }
        }

#if UNITY_EDITOR
        private void OnValidate()
        {
            if (mGraph != null && mGraph.asset != m_GraphAsset)
            {
                mGraph.Dispose();
                mGraph = null;
                if (m_GraphAsset != null)
                {
                    var graph = new TaskGraph(m_GraphAsset);
                    graph.name = name;
                    graph.SetOwner(this);
                    graph.StartGraph();
                    mGraph = graph;
                }
            }
            else if(Application.isPlaying && mGraph == null && isActiveAndEnabled && m_GraphAsset != null)
            {
                var graph = new TaskGraph(m_GraphAsset);
                graph.name = name;
                graph.SetOwner(this);
                graph.StartGraph();
                mGraph = graph;
            }
        }

        [ContextMenu("Debug Task Graph", true)]
        bool CanDebug()
        {
            return mGraph.IsValidInstance();
        }

        [ContextMenu("Debug Task Graph")]
        void DebugGraph()
        {
            if(mGraph != null)
            {
                TaskGraphAsset.OpenGraph(mGraph);
            }
        }
#endif
    }
}
